package com.sunlands.qdcy.deskmate.service.task;

import com.sunlands.qdcy.deskmate.dao.pojo.OrderRecordDO;
import com.sunlands.qdcy.deskmate.exception.SendExceptionUtil;
import com.sunlands.qdcy.deskmate.service.ApplePayService;
import com.sunlands.qdcy.deskmate.service.OrderRecordService;
import com.sunlands.qdcy.deskmate.util.SimpleLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

import static com.sunlands.qdcy.deskmate.config.RedisConfig.CacheKeys.*;

@Service
@Slf4j
@EnableScheduling
public class TaskServiceImpl {


    @Resource(name = "taskExecutor")
    private AsyncTaskExecutor taskExecutor;
    @Autowired
    private OrderRecordService orderRecordService;
    @Autowired
    private ApplePayService applePayService;
    @Autowired
    private SendExceptionUtil sendExceptionUtil;
    @Autowired
    private SimpleLockUtil simpleLockUtil;

    @Value("${eureka.debug:false}")
    private Boolean debug;

    @Resource(name = "checkUnPayExecutor")
    private AsyncTaskExecutor checkUnPayExecutor;

    @Resource(name = "sendGoodsExecutor")
    private AsyncTaskExecutor sendGoodsExecutor;


    /**
     * 查询最近二十四个小时的订单进行处理，防止历史异常订单过多，造成处理数据膨胀
     * 超过两个小时的订单，关闭交易
     */
    @Scheduled(cron = "${scheduled.checkOrder}")
    public void checkOrder() {
        if (debug) {
            log.warn("本地环境不启动定时");
            return;
        }

        if (!getCheckOrderLockKey()) {
            return;
        }

        log.info("定时检查订单数据任务开启");
        try {
            int i = 0;
            boolean flag = true;
            Page<OrderRecordDO> page = null;
            while (flag || page.hasNext()) {
                Pageable pageable = new PageRequest(i, 100);
                StopWatch stopWatch = new StopWatch();
                stopWatch.start("定时检查订单数据任务开启");
                flag = false;
                page = orderRecordService.findPayWaitingOrders(pageable);
                List<OrderRecordDO> orderList = page.getContent();
                i += orderList.size();
                long now = System.currentTimeMillis();
                orderList.forEach(order ->
                {
                    try {
                        Thread.sleep(20);
                        String outTradeNo = order.getOutTradeNo();
                        if(Objects.nonNull(order.getUpdateTime())){
                            long time = now - order.getUpdateTime().getTime();
                            //不处理刚刚10秒内有过更新的订单（大多数订单状态靠notice驱动，这个只做补偿处理）
                            if (time < 1000 * 10) {
                                return;
                            }
                        }
                        //24小时内的其他订单，从对应支付平台获取支付状态进行更新，已支付或者订单超时取消
                        checkUnPayExecutor.execute(() -> orderRecordService.pullOrderStatusAndDealOrder(outTradeNo));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                stopWatch.stop();
                i++;
                log.info("定时检查订单数据任务开启，本次处理数据条数 size = {} 总条数 = {} 耗时 = {}",page.getContent().size(), page.getTotalElements(), stopWatch.getTotalTimeMillis());
            }
        } catch (Exception e) {
            sendExceptionUtil.sendException("定时检查订单数据任务出错 错误信息 = " + e.getMessage(), e);
            log.error("定时检查订单数据任务出错！");
            log.error("", e);
        } finally {
            releaseCheckOrderLockKey();
        }

    }




    /**
     * 查询最近二十四个小时的订单已经支付却没有发货的进行发货
     */
    @Scheduled(cron = "${scheduled.sendGoods}")
    public void sendGoods() {
        if (debug) {
            log.warn("本地环境不启动定时");
            return;
        }

        if (!getSendGoodsLockKey()) {
            return;
        }

        log.info("定时检查订单是否已经发货");
        try {
            int i = 0;
            boolean flag = true;
            Page<OrderRecordDO> page = null;
            while (flag || page.hasNext()) {
                Pageable pageable = new PageRequest(i, 100);
                StopWatch stopWatch = new StopWatch();
                stopWatch.start("定时检查订单是否已经发货");
                flag = false;
                page = orderRecordService.findWaitingSendGoodsOrders(pageable);
                List<OrderRecordDO> orderList = page.getContent();
                i += orderList.size();
                long now = System.currentTimeMillis();
                orderList.forEach(order ->
                {
                    try {
                        Thread.sleep(20);
                        String outTradeNo = order.getOutTradeNo();
                        if(Objects.nonNull(order.getUpdateTime())){
                            long time = now - order.getUpdateTime().getTime();
                            //不处理刚刚10秒内有过更新的订单（大多数订单状态靠notice驱动，这个只做补偿处理）
                            if (time < 1000 * 10) {
                                return;
                            }
                        }
                        //24小时内的其他订单，从对应支付平台获取支付状态进行更新，已支付或者订单超时取消
                        sendGoodsExecutor.execute(() -> orderRecordService.sendGoods(outTradeNo));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                stopWatch.stop();
                i++;
                log.info("定时检查订单是否已经发货，本次处理数据条数 size = {} 总条数 = {} 耗时 = {}",page.getContent().size(), page.getTotalElements(), stopWatch.getTotalTimeMillis());
            }

            applePayService.verifyALlFailRecord();

        } catch (Exception e) {
            sendExceptionUtil.sendException("已支付订单发货处理任务出错 错误信息 = " + e.getMessage(), e);
            log.error("已支付订单发货处理任务出错！");
            log.error("", e);
        } finally {
            releaseSendGoodsLockKey();
        }

    }


    /**
     * 查询最近的退货订单，进行状态更新
     */
    @Scheduled(cron = "${scheduled.returnOrder}")
    public void checkReturnOrder() {
        if (debug) {
            log.warn("本地环境不启动定时");
            return;
        }

        if (!getReturnGoodsLockKey()) {
            return;
        }
        log.info("定时检查订单是否有退货");
        try {
            int i = 0;
            boolean flag = true;
            Page<OrderRecordDO> page = null;
            while (flag || page.hasNext()) {
                Pageable pageable = new PageRequest(i, 100);
                StopWatch stopWatch = new StopWatch();
                stopWatch.start("定时检查订单是否有退货");
                flag = false;
                page = orderRecordService.findPaySuccessOrders(pageable);
                List<OrderRecordDO> orderList = page.getContent();
                i += orderList.size();
                long now = System.currentTimeMillis();
                orderList.forEach(order ->
                {
                    try {

                        Thread.sleep(20);
                        String outTradeNo = order.getOutTradeNo();
                        if(Objects.nonNull(order.getUpdateTime())){
                            long time = now - order.getUpdateTime().getTime();
                            //不处理刚刚10秒内有过更新的订单（大多数订单状态靠notice驱动，这个只做补偿处理）
                            if (time < 1000 * 10) {
                                return;
                            }
                        }

                        try {
                            //24小时内的其他订单，从对应支付平台获取支付状态进行更新，已支付或者订单超时取消
                            applePayService.verifyReturnReceipt(order);
                        }catch (Exception e){
                            log.error("", e);
                        }

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                i++;
                stopWatch.stop();
                log.info("定时检查订单是否有退货，本次处理数据条数 size = {} 总条数 = {} 耗时 = {}",page.getContent().size(), page.getTotalElements(), stopWatch.getTotalTimeMillis());
            }
        } catch (Exception e) {
            sendExceptionUtil.sendException("查询退款订单出错 错误信息 = " + e.getMessage(), e);
            log.error("查询退款订单出错！");
            log.error("", e);
        } finally {
            releaseReturnGoodsLockKey();
        }

    }


    private boolean getCheckOrderLockKey() {
        String lockKey = CHECK_ORDER;
        try {
            return simpleLockUtil.acquireLock(lockKey, this.getClass().getName(), 30000);
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    private void releaseCheckOrderLockKey() {
        String lockKey = CHECK_ORDER;
        try {
            simpleLockUtil.releaseLock(lockKey, this.getClass().getName());
        } catch (Exception e) {
            log.error("releaseCheckOrderLockKey error", e);
        }
    }


    private boolean getSendGoodsLockKey() {
        String lockKey = SEND_GOODS;

        try {
            return simpleLockUtil.acquireLock(lockKey, this.getClass().getName(), 30000);
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    private void releaseSendGoodsLockKey() {
        String lockKey = SEND_GOODS;
        try {
            simpleLockUtil.releaseLock(lockKey, this.getClass().getName());
        } catch (Exception e) {
            log.error("releaseSendGoodsLockKey error", e);
        }
    }


    private boolean getReturnGoodsLockKey() {
        String lockKey = RETURN_GOODS;

        try {
            return simpleLockUtil.acquireLock(lockKey, this.getClass().getName(), 1000 * 60 * 30);
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    private void releaseReturnGoodsLockKey() {
        String lockKey = RETURN_GOODS;
        try {
            simpleLockUtil.releaseLock(lockKey, this.getClass().getName());
        } catch (Exception e) {
            log.error("releaseSendGoodsLockKey error", e);
        }
    }

}
